/*************************************************************/
/*                                                           */
/*     MC823 - Laboratorio de Teleprocessamento e Redes      */
/*     1 Semestre / 2013                                     */
/*     Projeto 1 - Cliente e Servidor TCP de uma Livraria    */
/*                                                           */
/*     Alunos: Joao Gabriel M.D.Mendes - RA 102788           */
/*             Lucas Domingues Lima    - RA 103140           */
/*                                                           */
/*************************************************************/

/* Arquivo: /cliente/tcp/cliente.c
   Definicao: representa o cliente em si, e o que sera
              executado de fato e chamara as demais rotinas.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <time.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "../requisicoes.h"
#include "../../sendrecv.h"

#define PORT "3491" // the port client will be connecting to 
/* NANO_PER_SECOND define o numero de nanosegundos em um segundo */
#define NANO_PER_SECOND		1000000000

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
	if (sa->sa_family == AF_INET) {
		return &(((struct sockaddr_in*)sa)->sin_addr);
	}

	return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[])
{
	int sockfd, numbytes,tam,opcao,n,contador[6];
	char *buf,*aux,**temp,id[100],arquivoLog[50],arquivoTempo[50];
	struct addrinfo hints, *servinfo, *p;
	int rv;
	char s[INET6_ADDRSTRLEN];
	FILE *arqLog,*arqTempo;
	struct timespec tstart;
	struct timespec tstop;
	float driftnano;
	
	//usage message
	if (argc != 3) {
	    fprintf(stderr,"uso: cliente hostname id\n");
	    exit(1);
	}

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
		return 1;
	}

	// loop through all the results and connect to the first we can
	for(p = servinfo; p != NULL; p = p->ai_next) {
		if ((sockfd = socket(p->ai_family, p->ai_socktype,
				p->ai_protocol)) == -1) {
			perror("client: socket");
			continue;
		}

		if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
			close(sockfd);
			perror("client: connect");
			continue;
		}

		break;
	}

	if (p == NULL) {
		fprintf(stderr, "client: failed to connect\n");
		return 2; 
	}

	inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),s, sizeof s);
	printf("client: connecting to %s\n", s);

	freeaddrinfo(servinfo); // all done with this structure

	sprintf(arquivoLog,"log/%s",argv[2]);
	sprintf(arquivoTempo,"tempo/%s",argv[2]);
	arqLog = fopen(arquivoLog,"w"); //abre arquivo de log do cliente
	arqTempo = fopen(arquivoTempo,"w"); //abre arquivo de tempo do cliente
	temp = carregaArquivo("../ISBNs.txt",&tam); //abre arquivo com ISBNs dos pedidos

  	//pega id do cliente
  	numbytes = strlen(argv[2]);
  	strcpy(id,argv[2]);
  	id[numbytes++] = '*';
  	id[numbytes] = '\0';

	//Manda mensagem inicial com o id do cliente
  	if(sendall(sockfd, id, &numbytes) == -1)
    perror("send");
	//espera a resposta do servidor dizendo que registrou corretamente
	if (recvall(sockfd, &buf,&numbytes) == -1) {
		perror("recv");
		exit(1);
	}
	free(buf);

  	for(n=0;n<6;n++)
		contador[n] = 0;
	n = 0;
	srandom(time(NULL));
	while(n < 600)
	{   
		opcao = random()%6 + 1;
        if(contador[opcao-1] < 100)
        {
        	aux = retornaRequisicao(opcao,temp,tam);
        	fprintf(arqLog,"Cliente: %s\n",aux);
        	numbytes = strlen(aux);
        	/* Primeiro, obtenho o tempo inicial. */
            clock_gettime(CLOCK_REALTIME, &tstart);
		    //Manda requisicao para o servidor
            if (sendall(sockfd, aux, &numbytes) == -1)
                perror("sendall");
            //Recebe a resposta do servidor
		    if (recvall(sockfd, &buf,&numbytes) == -1) 
		    {
            	perror("recvall");
            	exit(1);
		    }
              
            /* Para obter o tempo final */;
            clock_gettime(CLOCK_REALTIME, &tstop);
            /* Calcula-se o tempo gasto */
            driftnano = (float)(tstop.tv_sec - tstart.tv_sec);
            driftnano += (tstop.tv_nsec - tstart.tv_nsec)/(float)NANO_PER_SECOND;
			
		    /* Grava no arquivo */
            fprintf(arqTempo,"%d %.9f\n",opcao,driftnano);
            fprintf(arqLog,"Servidor: %s\n",buf);
            free(aux);
            free(buf);
            contador[opcao-1]++;
            n++;
    	}
	}

	//manda mensagem para o servidor dizendo que nao ha mais requisicoes
	numbytes = 2;
	if (sendall(sockfd, "0*", &numbytes) == -1)
		perror("sendall");

	desalocaVetorISBNs(temp,tam);
	fclose(arqLog);
	fclose(arqTempo);
	close(sockfd);

	return 0;
}